package com.baiyue.manager;

import com.alibaba.fastjson.JSONObject;
import com.baiyue.entity.CommodityConsumption;
import com.baiyue.entity.TollRules;
import com.baiyue.model.CashierResult;
import com.baiyue.model.MoneyResult;
import com.baiyue.model.commodityConsumption.CommodityConsumptionDataResponse;
import com.baiyue.model.tollRules.TollRulesDataResponse;
import org.apache.velocity.util.introspection.Uberspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.test.context.junit.jupiter.DisabledIf;

import java.math.BigDecimal;
import java.sql.Time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import static java.math.BigDecimal.ZERO;

/**
 * @author 伍波
 * @date 2024/5/1 19:19
 */
@Component
public class CashierManger {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 计算时间差，X小时X分钟
     * @param startTime
     * @param pauseTime 暂停开始时间
     * @param status 包间状态
     * @param subtractMinutes 暂停合计分钟数
     * @return
     */
    public CashierResult calculateTimeDuration(Date startTime,Date pauseTime,Integer status, Integer subtractMinutes,
                                               Date stopTime) {
        Date endTime = new Date();
        if (stopTime != null && status != 2){
            endTime = stopTime;
        }
        if (pauseTime != null && status == 2){
            endTime = pauseTime;
        }
        // 计算开始时间和结束时间之间的毫秒差
        long durationMillis = endTime.getTime() - startTime.getTime();
        // 将毫秒转换为分钟
        long totalMinutes = durationMillis / (60 * 1000);

        if (subtractMinutes != null){
            // 减去指定的分钟数
            totalMinutes -= subtractMinutes;
        }

        // 确保 totalMinutes 不为负数
        totalMinutes = Math.max(totalMinutes, 0);
        // 计算整数小时和整数分钟
        long hours = totalMinutes / 60;
        long minutes = totalMinutes % 60;

        CashierResult cashierResult = new CashierResult();
        cashierResult.setHour(hours);
        cashierResult.setMinute(minutes);
        return cashierResult;
    }

    /**
     * 计算分钟差
     * @param startTime
     * @return
     */
    public Integer calculateTimeDurationInMinutes(Date startTime, Date endTime) {
        logger.info("计算分钟差-开始时间：{} | 结束时间：{}",String.valueOf(startTime), String.valueOf(endTime));
        // 计算开始时间和结束时间之间的毫秒差
        long durationMillis = endTime.getTime() - startTime.getTime();
        // 将毫秒转换为分钟，并转换为 Integer 对象
        logger.info(String.valueOf((int)(durationMillis / (60 * 1000))));
        return (int)(durationMillis / (60 * 1000));
    }

    public MoneyResult computeHoursAndMinutesExpenses(CashierResult cashierResult, TollRulesDataResponse response,BigDecimal consumption) {
        long hour = cashierResult.getHour();
        long minute = cashierResult.getMinute();
        long nightHour = cashierResult.getNightHours();
        long nightMinute = cashierResult.getNightMinutes();
        long ruleTime = response.getRuleTime();
        long timeoutFreeTime = response.getTimeoutFreeTime();
        long timeoutMoney = response.getTimeoutMoney();
        long ruleMoney = response.getRuleMoney();
        long nightServeFreeTime = response.getNightServeFreeTime();
        long nightServeMoney = response.getNightServeMoney();

        logger.info("收到收银结果：" + hour + "小时，" + minute + "分钟。");

        // 如果费用为零，直接返回
        if (isZeroCost(hour, minute)) {
            MoneyResult result = new MoneyResult();
            if (!Objects.equals(consumption, ZERO)){
                result.setTotalAmount(consumption);
            }
            MoneyResult.TableFee tableFee = new MoneyResult.TableFee();
            tableFee.setTableFee(ZERO);
            result.setTableFee(Collections.singletonList(tableFee));
            return result;
        }

        MoneyResult result = calculateExpenses(hour, minute, ruleTime, timeoutFreeTime, timeoutMoney, ruleMoney,
                nightHour, nightMinute, nightServeFreeTime, nightServeMoney,consumption);
        logger.info("计算费用：{}", JSONObject.toJSONString(result));
        return result;
    }

    private boolean isZeroCost(long hour, long minute) {
        return hour <= 0 && minute <= 10;
    }

    public MoneyResult calculateExpenses(
            long hour, long minute, long ruleTime, long timeoutFreeTime, long timeoutMoney, long ruleMoney,
            long nightHour, long nightMinute, long nightServeFreeTime, long nightServeMoney,BigDecimal consumption) {

        long timeOut = Math.max(hour - ruleTime, 0);
        if (hour >= ruleTime && minute >= timeoutFreeTime) {
            timeOut += 1;
        }

        MoneyResult moneyResult = new MoneyResult();
        MoneyResult.TableFee tableFee = new MoneyResult.TableFee();
        List<MoneyResult.TableFee> list = new ArrayList<>();
        tableFee.setTableFee(BigDecimal.valueOf(ruleMoney));

        // 计算超时费用
        BigDecimal overtimeFee = timeOut == 0 ? ZERO : BigDecimal.valueOf(timeoutMoney).multiply(BigDecimal.valueOf(timeOut));
        tableFee.setOvertimeFee(overtimeFee);
        // 计算夜间服务费用
        BigDecimal nightServiceExpenses = BigDecimal.valueOf(nightHour).multiply(BigDecimal.valueOf(nightServeMoney));
        if (nightMinute >= nightServeFreeTime) {
            nightServiceExpenses = nightServiceExpenses.add(BigDecimal.valueOf(nightServeMoney));
        }
        tableFee.setNightFee(nightServiceExpenses);

        // 计算总费用
        BigDecimal expenses = BigDecimal.valueOf(ruleMoney).add(overtimeFee).add(nightServiceExpenses);
        moneyResult.setTotalAmount(expenses.add(consumption));

        if (timeOut == 0) {
            logger.info("无超时费用。");
        } else {
            logger.info("按照配置的规则加超时费用和夜间服务费用收费。");
        }
        list.add(tableFee);
        moneyResult.setTableFee(list);
        return moneyResult;
    }

    public CashierResult calculateNightServiceTime(
            Date startTime, Date nightStopTime, Time nightServeStart, Time nightServeEnd
    ) {
        CashierResult cashierResult = new CashierResult();
        Date stopTime = Objects.nonNull(nightStopTime) ? nightStopTime : new Date();

        long totalNightServiceDurationMinutes = 0;

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startTime);

        while (calendar.getTime().before(stopTime)) {
            // 获取当前时间的分钟表示
            long startMinutes = calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE);
            long endOfDayMinutes = 24 * 60; // 每天的分钟数
            long nightServeStartMinutes = nightServeStart.getHours() * 60 + nightServeStart.getMinutes();
            long nightServeEndMinutes = nightServeEnd.getHours() * 60 + nightServeEnd.getMinutes();

            // 计算夜间服务的开始时间和结束时间
            long nightServiceStart = Math.max(startMinutes, nightServeStartMinutes);
            long nightServiceEnd = Math.min(nightServeEndMinutes, endOfDayMinutes);

            // 如果当前日期是最后一天，需要考虑到 stopTime
            if (calendar.getTime().getYear() == stopTime.getYear() &&
                    calendar.getTime().getMonth() == stopTime.getMonth() &&
                    calendar.getTime().getDate() == stopTime.getDate()) {

                long stopMinutes = stopTime.getHours() * 60 + stopTime.getMinutes();
                nightServiceEnd = Math.min(nightServiceEnd, stopMinutes);
            }

            // 累加有效的夜间服务时长
            if (nightServiceStart < nightServiceEnd) {
                totalNightServiceDurationMinutes += nightServiceEnd - nightServiceStart;
            }

            // 移动到下一天的夜间服务时间段
            calendar.add(Calendar.DAY_OF_MONTH, 1);
            calendar.set(Calendar.HOUR_OF_DAY, nightServeStart.getHours());
            calendar.set(Calendar.MINUTE, nightServeStart.getMinutes());
        }

        // 将总的夜间服务时长转换为小时和分钟
        long nightHours = totalNightServiceDurationMinutes / 60;
        long nightMinutes = totalNightServiceDurationMinutes % 60;

        // 设置结果
        cashierResult.setNightHours(nightHours);
        cashierResult.setNightMinutes(nightMinutes);

        logger.info("夜间服务时间：{}",JSONObject.toJSONString(cashierResult));
        return cashierResult;
    }

    /**
     * 计算商品消费总金额
     * @param responseList
     * @return
     */
    public BigDecimal computeConsumption(List<CommodityConsumptionDataResponse> responseList) {
        BigDecimal totalConsumption = ZERO;
        if (responseList.isEmpty()) {
            return totalConsumption;
        }
        for (CommodityConsumptionDataResponse commodityConsumption : responseList) {
            totalConsumption = totalConsumption.add(commodityConsumption.getTotalAmount());
        }
        return totalConsumption;
    }
}

